package com.primus.server.service;

import com.google.common.collect.Lists;
import com.primus.server.entity.BaseEntity;
import com.primus.server.exception.ApplicationException;
import org.springframework.beans.BeanUtils;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

public abstract class BaseServiceImpl<T extends BaseEntity> implements BaseService<T> {

    protected abstract JpaRepository<T, Long> getRepository();

    @Override
    public List<T> findAll() {
        return Lists.newArrayList(this.getRepository().findAll());
    }

    @Override
    public Page<T> findAllWithPagination(Pageable pageable) {
        return this.getRepository().findAll(pageable);
    }

    @Override
    public T findById(Long id) {
        return this.getRepository().findById(id).orElseThrow(() -> {
            String message = String.format("Can not found [%s] with id [%s]", "Entity", String.valueOf(id));
            return new ApplicationException(message);
        });
    }

    @Override
    @Transactional
    public T save(T t) {
        return this.getRepository().save(t);
    }

    @Override
    @Transactional
    public void delete(BaseEntity entity) {
        this.deleteById(entity.getId());
    }

    @Override
    @Transactional
    public void deleteAll(Iterable<T> entities) {
        this.getRepository().deleteAll(entities);
    }

    @Override
    @Transactional
    public void deleteById(Long id) {
        this.getRepository().deleteById(id);
    }

    @Override
    @Transactional
    public T upsert(T newEntity, Long id) {
        return getRepository().findById(id).map(entity -> {
            BeanUtils.copyProperties(newEntity, entity, "id");
            return getRepository().save(entity);
        }).orElseGet(() -> {
            return getRepository().save(newEntity);
        });
    }

    @Override
    @Transactional
    public void saveAll(List<T> list) {
        this.getRepository().saveAll(list);
    }
}
